package com.usian.search.service.impl;

import com.usian.article.client.ArticleFeign;
import com.usian.common.enums.AppHttpCodeEnum;
import com.usian.common.exception.LeadException;
import com.usian.common.threadlocal.UserThreadLocalUtils;
import com.usian.common.util.JsonUtils;
import com.usian.model.article.dtos.ArticleDto;
import com.usian.model.article.dtos.AuthorDto;
import com.usian.model.search.dtos.UserSearchDto;
import com.usian.search.service.ApArticleSearchService;
import com.usian.search.service.IApUserSearchService;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ApArticleSearchServiceImpl implements ApArticleSearchService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    private String indexName = "app_info_article";

    @Override
    public void createIndex(ArticleDto dto) {
        //封装索引库需要的数据
        Map<String,Object> map = new HashMap<>();
        map.put("id",dto.getId());
        map.put("publishTime", dto.getPublishTime());
        map.put("layout", dto.getLayout());
        map.put("images", dto.getImages());
        map.put("authorId", dto.getAuthorId());
        map.put("title", dto.getTitle());
        //将map转为json字符串
        String articleJson = JsonUtils.toString(map);

        //将数据存入索引库
        IndexRequest indexRequest = new IndexRequest(indexName).id(dto.getId().toString());
        //将请求对象关联组装的数据
        indexRequest.source(articleJson,XContentType.JSON);

        try {
            restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR,"同步文章数据到索引库失败");
        }

    }

    @Autowired
    private IApUserSearchService apUserSearchService;

    @Override
    public List<ArticleDto> articleSearch(UserSearchDto dto) {
        //获取用户id
        Integer userId = UserThreadLocalUtils.getUserId();
        //异步记录搜索历史
        apUserSearchService.saveUserSearch(dto,userId);

        //1、参数校验
        if(dto==null){
            throw new LeadException(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        //2、封装查询条件
        SearchRequest searchRequest = new SearchRequest(indexName);
        //创建查询构建器（封装查询条件）
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        //封装组合查询条件
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //根据关键字，匹配查询文章标题
        boolQuery.must(QueryBuilders.matchQuery("title",dto.getSearchWords()).operator(Operator.AND));
        //文章列表最小发布时间，小于当前时间
        if(dto.getMinBehotTime() != null){
            boolQuery.filter(QueryBuilders.rangeQuery("publishTime").lte(dto.getMinBehotTime()));
        }
        //将封装的查询条件关联到查询构建器
        sourceBuilder.query(boolQuery);
        //设置分页条件
        sourceBuilder.from(dto.getFromIndex());
        sourceBuilder.size(dto.getPageSize());
        //按照发布时间倒序排序
        sourceBuilder.sort("publishTime", SortOrder.DESC);

        //将查询请求对象，关联到查询构建器
        searchRequest.source(sourceBuilder);
        //3、执行查询
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR,"搜索文章失败");
        }
        //4、组装查询结果
        SearchHits searchHits = searchResponse.getHits();
        //获取查询结果集
        SearchHit[] hits = searchHits.getHits();
        List<ArticleDto> articleList = new ArrayList<>();
        for (SearchHit hit : hits) {
            //获取文章数据
            String source = hit.getSourceAsString();
            ArticleDto articleDto = JsonUtils.toBean(source, ArticleDto.class);
            articleList.add(articleDto);
        }

        return articleList;
    }

    @Autowired
    private ArticleFeign articleFeign;

    @Override
    public void importArticleToEs(Long articleId) {
        ArticleDto articleDto = articleFeign.findArticleById(articleId);
        //同步文章到索引库
        this.createIndex(articleDto);
    }

    @Override
    public void ArticleUpDown(Integer wmNewsId, Integer enable) {
        //根据自媒体文章id查询App文章
        ArticleDto articleDto = articleFeign.findArticleByWmNewsId(wmNewsId);
        if(enable==1){
            //上架
            this.createIndex(articleDto);
        }else{
            //下架
            deleteIndex(articleDto.getId());
        }
    }

    //删除索引库
    private void deleteIndex(Long articleId){
        DeleteRequest deleteRequest = new DeleteRequest(indexName).id(articleId.toString());
        try {
            restHighLevelClient.delete(deleteRequest,RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
